<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>05_深拷贝和浅拷贝-循环引用</title>
  </head>

  <body>
    <script>
      function isObject(value) {
        const valueType = typeof value
        return (
          value !== null && (valueType === 'object' || valueType === 'function')
        )
      }
    </script>
    <script>
      function deepClone(origin, map = new WeakMap()) {
        // Symbol类型
        if (typeof origin === 'symbol') {
          return Symbol(origin.description)
        }

        // 函数类型
        if (typeof origin === 'function') {
          return origin
        }

        // RegExp类型
        if (origin instanceof RegExp) {
          return new RegExp(origin.source, origin.flags)
        }

        // Date类型
        if (origin instanceof Date) {
          return new Date(origin)
        }

        if (!isObject(origin)) return origin

        // set类型
        if (origin instanceof Set) {
          // return new Set([...origin])
          const newSet = new Set()
          for (const item of origin) {
            newSet.add(deepClone(item))
          }
          return newSet
        }

        // 4.如果是对象类型，则判断是否循环引用, 才需要创建对象
        if (map.has(origin)) {
          // console.log(map.get(origin), origin);
          return map.get(origin)
        }

        const newObj = Array.isArray(origin) ? [] : {}
        // console.log("newObj", newObj);
        // map.set(origin, newObj): 表示origin对象映射到newObj对象
        map.set(origin, newObj)
        for (const key in origin) {
          newObj[key] = deepClone(origin[key], map)
        }

        // 单独遍历symbol
        const symbolKeys = Object.getOwnPropertySymbols(origin)
        for (const sKey of symbolKeys) {
          console.log(sKey)

          newObj[Symbol(symbolKeys.description)] = deepClone(origin[sKey], map)
        }

        return newObj
      }

      const set = new Set(['abc', 'cba', 'nba'])
      const map = new Map([
        ['a', 1],
        ['b', 2],
      ])
      const s1 = Symbol('s1')
      const s2 = Symbol('s2')
      const obj = {
        name: 'deepClone',
        age: 18,
        address: {
          city: '北京',
          home: {
            name: 'home',
          },
        },
        arr: [1, 2, 3],

        // 1.特殊类型: Set
        set: set,

        // 2.特性类型: function
        running: function () {
          console.log('running~')
        },

        // 3.值的特殊类型: Symbol
        symbolKey: Symbol('abc'),

        // 4.key是symbol时
        [s1]: 'aaaa',
        [s2]: 'bbbb',

        // 5. map类型
        map: map,
      }
      obj.info = obj

      const newObj = deepClone(obj)
      obj.age = 99

      console.log(obj, newObj)
      // console.log(set instanceof Set, isObject(s2));
    </script>
  </body>
</html>
